home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / PACK_NAM.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  10KB  |  497 lines

  1. /*
  2.  *     pack_name(packed, name, length)
  3.  *    pack sender's name into something sensible, return in packed
  4.  *
  5.  */
  6.  
  7. #include "config.h"
  8.  
  9.  
  10. #define    SEP_DOT        0    /* . */
  11. #define    SEP_PERCENT    1    /* % */
  12. #define    SEP_SCORE    2    /* _ */
  13. #define    SEP_AMPERSAND    3    /* @ */
  14. #define    SEP_BANG    4    /* ! */
  15. #define    SEP_MAXIMUM    5
  16.  
  17.  
  18. #define CL_OK        0x0100        /* letter or digit */
  19. #define CL_SPACE    0x0200        /* cvt to space */
  20. #define CL_IGNORE    0x0400        /* ignore */
  21. #define CL_RANGE(c)    0x0800+c    /* space range, end with c */
  22. #define CL_HYPHEN    0x1000        /* convert to - */
  23. #define CL_STOP        0x2000        /* discard rest of name */
  24. #define    CL_SEP        | 0x4000 +        /* address separator */
  25.  
  26. #define    IS_OK(c)    (Class[c] & CL_OK)
  27. #define IS_SPACE(c)    (Class[c] & CL_SPACE)
  28. #define IGNORE(c)    (c & 0x80 || Class[c] & CL_IGNORE)
  29. #define BEGIN_RANGE(c)    (Class[c] & CL_RANGE(0))
  30. #define END_RANGE(c)    (Class[c] & 0xff)
  31. #define IS_HYPHEN(c)    (Class[c] & CL_HYPHEN)
  32. #define IS_STOP(c)    (Class[c] & CL_STOP)
  33. #define    IS_SEPARATOR(c)    (Class[c] & (0 CL_SEP 0))
  34.     
  35. static short Class[128] = {
  36.     /* NUL */        CL_STOP ,
  37.     /* SOH */        CL_IGNORE ,
  38.     /* STX */        CL_IGNORE ,
  39.     /* ETX */        CL_IGNORE ,
  40.     /* EOT */        CL_IGNORE ,
  41.     /* ENQ */        CL_IGNORE ,
  42.     /* ACK */        CL_IGNORE ,
  43.     /* BEL */        CL_IGNORE ,
  44.     /* BS  */        CL_IGNORE ,
  45.     /* TAB */        CL_SPACE ,
  46.     /* NL  */        CL_IGNORE ,
  47.     /* VT  */        CL_IGNORE ,
  48.     /* FF  */        CL_IGNORE ,
  49.     /* CR  */        CL_IGNORE ,
  50.     /* SO  */        CL_IGNORE ,
  51.     /* SI  */        CL_IGNORE ,
  52.     /* DLE */        CL_IGNORE ,
  53.     /* DC1 */        CL_IGNORE ,
  54.     /* DC2 */        CL_IGNORE ,
  55.     /* DC3 */        CL_IGNORE ,
  56.     /* DC4 */        CL_IGNORE ,
  57.     /* NAK */        CL_IGNORE ,
  58.     /* SYN */        CL_IGNORE ,
  59.     /* ETB */        CL_IGNORE ,
  60.     /* CAN */        CL_IGNORE ,
  61.     /* EM  */        CL_IGNORE ,
  62.     /* SUB */        CL_IGNORE ,
  63.     /* ESC */        CL_IGNORE ,
  64.     /* FS  */        CL_IGNORE ,
  65.     /* GS  */        CL_IGNORE ,
  66.     /* RS  */        CL_IGNORE ,
  67.     /* US  */        CL_IGNORE ,
  68.     
  69.     /* space */        CL_SPACE ,
  70.     /*   !   */        CL_SPACE CL_SEP SEP_BANG,
  71.     /*   "   */        CL_RANGE( '"' ) ,
  72.     /*   #   */        CL_OK ,
  73.     /*   $   */        CL_OK ,
  74.     /*   %   */        CL_OK CL_SEP SEP_PERCENT,
  75.     /*   &   */        CL_OK ,
  76.     /*   '   */        CL_OK ,
  77.     /*   (   */        CL_RANGE( ')' ) ,
  78.     /*   )   */        CL_IGNORE ,
  79.     /*   *   */        CL_HYPHEN ,
  80.     /*   +   */        CL_HYPHEN ,
  81.     /*   ,   */        CL_STOP ,
  82.     /*   -   */        CL_HYPHEN ,
  83.     /*   .   */        CL_SPACE CL_SEP SEP_DOT,
  84.     /*   /   */        CL_OK ,
  85.     /*   0   */        CL_OK ,
  86.     /*   1   */        CL_OK ,
  87.     /*   2   */        CL_OK ,
  88.     /*   3   */        CL_OK ,
  89.     /*   4   */        CL_OK ,
  90.     /*   5   */        CL_OK ,
  91.     /*   6   */        CL_OK ,
  92.     /*   7   */        CL_OK ,
  93.     /*   8   */        CL_OK ,
  94.     /*   9   */        CL_OK ,
  95.     /*   :   */        CL_IGNORE ,
  96.     /*   ;   */        CL_STOP ,
  97.     /*   <   */        CL_IGNORE ,
  98.     /*   =   */        CL_HYPHEN ,
  99.     /*   >   */        CL_IGNORE ,
  100.     /*   ?   */        CL_IGNORE ,
  101.     /*   @   */        CL_OK CL_SEP SEP_AMPERSAND,
  102.     /*   A   */        CL_OK ,
  103.     /*   B   */        CL_OK ,
  104.     /*   C   */        CL_OK ,
  105.     /*   D   */        CL_OK ,
  106.     /*   E   */        CL_OK ,
  107.     /*   F   */        CL_OK ,
  108.     /*   G   */        CL_OK ,
  109.     /*   H   */        CL_OK ,
  110.     /*   I   */        CL_OK ,
  111.     /*   J   */        CL_OK ,
  112.     /*   K   */        CL_OK ,
  113.     /*   L   */        CL_OK ,
  114.     /*   M   */        CL_OK ,
  115.     /*   N   */        CL_OK ,
  116.     /*   O   */        CL_OK ,
  117.     /*   P   */        CL_OK ,
  118.     /*   Q   */        CL_OK ,
  119.     /*   R   */        CL_OK ,
  120.     /*   S   */        CL_OK ,
  121.     /*   T   */        CL_OK ,
  122.     /*   U   */        CL_OK ,
  123.     /*   V   */        CL_OK ,
  124.     /*   W   */        CL_OK ,
  125.     /*   X   */        CL_OK ,
  126.     /*   Y   */        CL_OK ,
  127.     /*   Z   */        CL_OK ,
  128.     /*   [   */        CL_OK ,
  129.     /*   \   */        CL_OK ,
  130.     /*   ]   */        CL_OK ,
  131.     /*   ^   */        CL_IGNORE ,
  132.     /*   _   */        CL_SPACE CL_SEP SEP_SCORE,
  133.     /*   `   */        CL_IGNORE ,
  134.     /*   a   */        CL_OK ,
  135.     /*   b   */        CL_OK ,
  136.     /*   c   */        CL_OK ,
  137.     /*   d   */        CL_OK ,
  138.     /*   e   */        CL_OK ,
  139.     /*   f   */        CL_OK ,
  140.     /*   g   */        CL_OK ,
  141.     /*   h   */        CL_OK ,
  142.     /*   i   */        CL_OK ,
  143.     /*   j   */        CL_OK ,
  144.     /*   k   */        CL_OK ,
  145.     /*   l   */        CL_OK ,
  146.     /*   m   */        CL_OK ,
  147.     /*   n   */        CL_OK ,
  148.     /*   o   */        CL_OK ,
  149.     /*   p   */        CL_OK ,
  150.     /*   q   */        CL_OK ,
  151.     /*   r   */        CL_OK ,
  152.     /*   s   */        CL_OK ,
  153.     /*   t   */        CL_OK ,
  154.     /*   u   */        CL_OK ,
  155.     /*   v   */        CL_OK ,
  156.     /*   w   */        CL_OK ,
  157.     /*   x   */        CL_OK ,
  158.     /*   y   */        CL_OK ,
  159.     /*   z   */        CL_OK ,
  160.     /*   {   */        CL_OK ,
  161.     /*   |   */        CL_OK ,
  162.     /*   }   */        CL_OK ,
  163.     /*   ~   */        CL_HYPHEN ,
  164.     /*  DEL  */        CL_IGNORE 
  165. } ;
  166.  
  167.  
  168. pack_name(dest, source, length)
  169. char *dest, *source;
  170. int length;
  171. {
  172.     register char *p, *q, *r, c;
  173.     register int n;
  174.     char namebuf[129], *name;
  175.     char *maxq;
  176.     int lname, lfirst, lmiddle, llast, sep, i;
  177.     int drop_space, prev_space;
  178.     char *separator[SEP_MAXIMUM];
  179.     
  180.     dest[0] = NUL;
  181.     
  182.     if (source == NULL || source[0] == NUL)
  183.     return 0;
  184.  
  185.     p = source, q = namebuf, n = 0;
  186.     maxq = namebuf + sizeof namebuf - 1;
  187.     
  188. new_partition:
  189.     for (i = SEP_MAXIMUM; --i >= 0; separator[i] = NULL);
  190.     
  191.     while ( c = *p++ ) {
  192.     if (c == '<') {
  193.         while (q > namebuf && q[-1] == SP) q--;
  194.         if (q == namebuf) continue;
  195.         break;
  196.     }
  197.     if (IGNORE(c)) continue;
  198.     if (q == namebuf && IS_SPACE(c)) continue;
  199.     if (c == '(') {
  200.         if (*p == ')') {
  201.         p++;
  202.         continue;
  203.         }
  204.         if (n++ == 0) {
  205.         q = namebuf;
  206.         goto new_partition;
  207.         }
  208.         continue;
  209.     }
  210.     if (c == ')') {
  211.         if (--n == 0) break;
  212.         continue;
  213.     }
  214.     if (n > 1) continue;
  215.     if (q >= maxq) break;
  216.     *q++ = c;
  217.     if (IS_SEPARATOR(c)) {
  218.         switch (sep = (Class[c] & 0xff)) {
  219.         
  220.          case SEP_DOT:
  221.         if (separator[SEP_AMPERSAND] && q - namebuf <= length)
  222.             break;
  223.         continue;
  224.  
  225.          case SEP_BANG:
  226.         if (separator[SEP_AMPERSAND]) continue;
  227.         break;
  228.         
  229.          default:
  230.         if (separator[sep]) continue;
  231.         break;
  232.         }
  233.         
  234.         separator[sep] = q - 1;
  235.     }
  236.     }
  237.  
  238.     *q = NUL;
  239.     
  240.     if (namebuf[0] == NUL) return 0;
  241.     
  242.     name = namebuf;
  243.  
  244.     if (name[0] == '"') {
  245.     name++;
  246.     if (q[-1] == '"') *--q = NUL;
  247.     }
  248.     
  249.     if (q - name <= length) goto name_ok;
  250.     
  251.     /* sorry for the many goto's -- the 3B2 C compiler does not */
  252.     /* make correct code for complicated logical expressions!!  */
  253.     /* not even without -O                    */
  254.  
  255.     /* We must pack the name to make it fit */
  256.     
  257.     /* Name_of_person%... -> Name_of_person */
  258.  
  259.     if (r = separator[SEP_PERCENT]) {
  260.     if (!(q = separator[SEP_SCORE]) || q > r ) 
  261.         goto no_percent;
  262.     if ((q = separator[SEP_AMPERSAND]) && q < r)
  263.         goto no_percent;
  264.     if ((q = separator[SEP_BANG]) && q < r)
  265.         goto no_percent;
  266.     *r = NUL;
  267.     goto parse_name;
  268.     }
  269.  
  270.  no_percent:
  271.  
  272.     /* name@site.domain -> name@site */
  273.  
  274.    if (r = separator[SEP_AMPERSAND]) {
  275.  
  276.        if ((q = separator[SEP_PERCENT]) && q < r) {
  277.        *r = NUL;
  278.        if (r - name <= length) goto name_ok;
  279.  
  280.        *q = NUL;
  281.  
  282.        if (((p = separator[SEP_BANG]) && p < q)
  283.          || ((p = strrchr(name, '!')) && p < q)) {
  284.            name = p + 1;
  285.        }
  286.  
  287.        if (strchr(name, '.')) 
  288.            goto parse_name;
  289.        
  290.        goto name_ok;
  291.        }
  292.  
  293.        if (q = separator[SEP_DOT]) {
  294.        *q = NUL;
  295.        goto name_ok;
  296.        }    
  297.     
  298.        *r = NUL;
  299.        if (r - name <= length) goto name_ok;
  300.        
  301.        if ((q = separator[SEP_BANG]) && q < r) {
  302.        name = q + 1;
  303.        goto name_ok;
  304.        }
  305.  
  306. #ifdef NOTDEF
  307.        if (strchr(name, '!') == NULL) 
  308.        goto parse_name; /* take the chance ... */
  309. #endif
  310.     goto name_ok;    /* can't do it any better */
  311.     }
  312.     
  313.     
  314.     /* Phase 1: Normalization (remove superfluous characters) */
  315.     
  316.  parse_name:
  317.     
  318.     for (p = name, lname = 0, prev_space = 0; c = *p; p++) {
  319.  
  320. /*    
  321.     if (IGNORE(c)) {
  322.         *p = TAB;
  323.         if (p == name) name++;
  324.         continue;
  325.     }
  326. */
  327.     
  328.     if (IS_OK(c)) {
  329.         lname++;
  330.         prev_space = 0;
  331.         continue;
  332.     }
  333.     
  334.     if (IS_HYPHEN(c)) {
  335.         if (p == name) {
  336.         name++;
  337.         continue;
  338.         }
  339.         if (prev_space)
  340.         *p = TAB;
  341.         else {
  342.         *p = '-';
  343.         lname++;
  344.         }
  345.         continue;
  346.     }
  347.     
  348.     if (BEGIN_RANGE(c)) {
  349.         
  350.         if (p == name) {
  351.         name++;
  352.         continue;
  353.         }
  354.         
  355.         c = END_RANGE(c);
  356.         for (q = p+1; *q && *q != c; q++);
  357.         if (*q) {
  358.         if (p[-1] != ' ') lname++;
  359.         while (p <= q) *p++ = ' ';
  360.         p--;
  361.         prev_space++;
  362.         continue;
  363.         }
  364.         c = ' ';
  365.     }
  366.     
  367.     if (IS_SPACE(c)) {
  368.         *p = ' ';
  369.         if (p == name) 
  370.         name++;
  371.         else
  372.         if (!prev_space) {
  373.             lname++;
  374.             prev_space++;
  375.         }
  376.         continue;
  377.     }
  378.     
  379.     if (IS_STOP(c)) {
  380.         *p = NUL;
  381.         break;
  382.     }
  383.     }
  384.  drop_last_name:
  385.     while (p > name && (*--p == ' ' || *p == TAB)) *p = NUL;
  386.     
  387.     if (lname < length) goto name_ok;
  388.     
  389.     
  390.     /* Phase 2: Reduce middle names */
  391.     
  392.     for (r = p, llast = 0; r > name && *r != ' '; r--)
  393.     if (*r != TAB) llast++;
  394.     
  395.     /* r points to space before last name */
  396.     
  397.     if (strncmp(r, " Jr", 3) == 0 || strncmp(r, " II", 3) == 0) {
  398.     p = r+1;
  399.     lname -= llast;
  400.     goto drop_last_name;
  401.     }        
  402.     
  403.     if (r == name) goto phase6;    /* only last name */
  404.     
  405.     for (q = name, lfirst = 0; *q && *q != ' '; q++)
  406.     if (*q != TAB) lfirst++;
  407.     
  408.     /* q points at space after first name */
  409.     
  410.     for (p = q, lmiddle = 0; p < r; ) {
  411.     /* find next middle name */
  412.     while (p < r && (*p == ' ' || *p == TAB)) p++;
  413.     
  414.     if (p >= r) break; /* found last name */
  415.     
  416.     p++; /* skip first char of middle name */
  417.     for (;*p != ' '; p++) { /* remove rest */
  418.         if (*p == TAB) continue;
  419.         *p = TAB;
  420.         lname--;
  421.     }
  422.     lmiddle += 2;    /* initial + space */
  423.     }
  424.     
  425.     if (lname < length) goto name_ok;
  426.     
  427.     /* If removing middle names is not enough, but reducing first name instead is, do it that way */
  428.     
  429.     if (lname - lmiddle >= length && lname - lfirst + 1 < length) goto phase4;
  430.     
  431.     
  432.     /* Phase 3: Remove middle names */
  433.     
  434.     for (p = q; p < r; p++) {
  435.     if (*p == TAB) continue;
  436.     if (*p == ' ') continue;
  437.     *p = TAB;
  438.     lname -= 2;
  439.     }
  440.     
  441.     if (lname < length) goto name_ok;
  442.     
  443.     
  444.     /* Phase 4: Reduce first name */
  445.     
  446.  phase4:
  447.     for (p = name+1; p < q; p++) {
  448.     if (*p == TAB) continue;
  449.     if (*p == ' ') continue;
  450.     if (*p == '-' && (p + 1) < q) {
  451.         p++;
  452.         continue;
  453.     }
  454.     *p = TAB;
  455.     lname--;
  456.     }
  457.     
  458.     if (lname < length) goto name_ok;
  459.     
  460.     /* Phase 5: Remove first name */
  461.     
  462.     name = r+1;
  463.     lname--;
  464.     
  465.     if (lname < length) goto name_ok;
  466.     
  467.     /* Phase 6: Cut last name */
  468.  phase6:
  469.     goto name_ok;
  470.     
  471.  name_ok:
  472.  
  473.     q = dest;
  474.     maxq = q + length;
  475.  
  476.     drop_space = 1;
  477.     
  478.     for (p = name; *p && q < maxq ; p++) {
  479.     if (*p == TAB) continue;
  480.     
  481.     if ( *p == ' ' ) {
  482.         if (!drop_space) {
  483.         drop_space = 1;
  484.         *q++ = ' ';
  485.         }
  486.         continue;
  487.     }
  488.     drop_space = 0;
  489.     *q++ = *p;
  490.     }
  491.     
  492.     *q = NUL;
  493.     
  494.     return strlen(dest);
  495. }    
  496.  
  497.